/* Autostop
 *
 * Copyright (c) 2006 - 2007 Maciej Gajewski, Grzegorz Latarowski
 * http://code.google.com/p/autostop-automaty-drogowe
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version. NO WARRANTY OF ANY KIND is expressed or implied.
 */

///@file process.c analyze process rutines

#include <assert.h>			// uses assert()
#include <stdlib.h>			// uses malloc/free
#include <stdio.h>
#include <string.h>
#include <math.h>

#include "analyzer.h"		// main definitions
#include "drawing.h"		// drawing output

// min/max defnitions. note - these aree gcc-only
#define min(i,j)	((i) < (j) ? (i) : (j))
#define max(i,j)	((i) > (j) ? (i) : (j))

// module locals
static process_params_t default_params();						///< returns default params
/// Process stage 1 - from regular image to segmented map
static void process_phase1( pprocess_t pprocess,  const pimage_t pimage, int delta_time );
/// Process stage 2 - from segmented image to groups
static void process_phase2( pprocess_t pprocess );
/// Process stage 3 - from groups to moving objects
static void process_phase3( pprocess_t pprocess, pimage_t pimage, uint64_t timestamp );
/// Initializes group structure
static void init_group( group_t& pgroup );
/// Merges two groups
static void merge_groups( group_t& lower, group_t& higher );
/// Adds pixel to group
static void add_pixel_to_group( group_t& pgroup, int x, int y, pixel_t value );


// ============================================================
/// Creates and initializes process. Assign default values to process params
pprocess_t create_process()
{
	// alocate process struct
	pprocess_t pprocess = new process_t();

	// initialize data
	assert( pprocess );

	pprocess->params			= default_params();
	pprocess->pbackground		= NULL;
	pprocess->psegmented		= NULL;
	pprocess->pgroupmap			= NULL;
	pprocess->processed_frames	= 0;
	pprocess->debug_draw		= 0;

	// reference distance
	pprocess->pdistance_markers			= NULL;
	pprocess->pshutter_markers			= NULL;
	pprocess->pROI						= NULL;
	pprocess->reference_distance			= 0;

	return pprocess;
}

// ============================================================
/// Frees process. Does nothing if pprocess is NULL
///@param pprocess process to free
void free_process( pprocess_t pprocess )
{
	if( pprocess ) {
	
		// free sub-structures
		free_image( pprocess->pbackground );
		free_image( pprocess->psegmented );

		free_map( pprocess->pgroupmap );
		
		// free user-supplied reference distances
		free_image( pprocess->pdistance_markers );
		free_image( pprocess->pshutter_markers );
		
		// free master struct
		delete pprocess;
	}
}

// ============================================================
/// Returns default process parameters
static process_params_t default_params()
{
	process_params_t params;
	params.background_factor		= 0.02*0.05;	// 1/50 blend in 1/20 sek
	params.foreground_treshold		= 85;
	params.segmentation_scale_log	= 3;	// real scale - 8
	params.segment_treshold			= 16;	// 32/255
	params.max_group_size			= 256;	// [px]
	params.min_group_size			= 32;	// [px]
	params.max_group_distance		= 640;	// [px/s]
	params.object_timeout			= 15*1000;// [ms] // TODO make shorter. long for debugging

	return params;
} 

// ============================================================
/// Adds image to running process. The image is processed, and process results may
/// be read from process then.
///\par
/// First image added to process determines image size. All subsequent image have to
/// be the same size.
///
/// n debug mode, internal data (groups etc) will be painted at the image
///\param pprocess	running process. Must be a valid pointer
///\param pimage	new image. Must be a valid pointer.
///\param timestamp	image timestamp [ms]
///\note this function is time critical
void add_frame( pprocess_t pprocess, pimage_t pimage, uint64_t timestamp )
{
	assert( pprocess );
	assert( pimage );

	// first image
	if ( pprocess->processed_frames == 0 ) {
		assert( ! pprocess->pbackground );
		
		// intial calculations
		pprocess->_int_background_factor = (int)( (1<<16) * pprocess->params.background_factor );
		// create background - copy
		pprocess->pbackground = create_image_copy( pimage );
		// create empty segmented image
		pprocess->psegmented = create_image
			( pimage->width		>> pprocess->params.segmentation_scale_log
			, pimage->height	>> pprocess->params.segmentation_scale_log
			);
		// create array for group indexes
		pprocess->pgroupmap = create_map( pprocess->psegmented->width, pprocess->psegmented->height );
		
	}
	// subsequent images
	else {
		assert( pprocess->pbackground );
		assert( pimage->width = pprocess->pbackground->width );
		assert( pimage->height = pprocess->pbackground->height );

		// calculate timespan
		int delta_time = timestamp - pprocess->last_frame_time;

		// phase 1 - get segmented image
		process_phase1( pprocess, pimage, delta_time );
		// phase 2 - get groups
		process_phase2( pprocess );
		// phase 3 - update objects with groups
		process_phase3( pprocess, pimage, timestamp );
	}

	// store timestamp and increment counter
	pprocess->last_frame_time = timestamp;
	pprocess->processed_frames ++;
}

// ============================================================
/// Processes incoming preprocessed frame. Utilizes hardware aceleration, which 
/// does phase1. Phase 1 and bckgorund initialization are not neccesary, only phases 2 and 3 
/// Are done.
///\param pprocess	running process. Must be a valid pointer
///\param pimage	new image. Must be a valid pointer.
///\param timestamp	image timestamp [ms]
///\note this function is time critical
void add_segmented_frame( pprocess_t pprocess, pimage_t psegmented, uint64_t timestamp )
{
	assert( pprocess );
	assert( psegmented );

	// first image
	if ( pprocess->processed_frames == 0 ) {
		
		// create array for group indexes
		pprocess->pgroupmap = create_map( psegmented->width, psegmented->height );
		
	}
	// subsequent images
	else {
		// gets segmented image from param
		pprocess->psegmented = psegmented;
		// phase 2 - get groups
		process_phase2( pprocess );
		// phase 3 - update objects with groups
		process_phase3( pprocess, 0, timestamp );
	}

	// store timestamp and increment counter
	pprocess->last_frame_time = timestamp;
	pprocess->processed_frames ++;
}

// ============================================================
/// Processes incoming image:
///	- updates background storeed in process context
///	- creates segemented image in process context
///\param	pprocess		- process context
///\param	pimage		- incoming frame
///\param	delta_time	- time from last background update [ms]
///\note	This function is time-critical
static void process_phase1( pprocess_t pprocess,  const pimage_t pimage, int delta_time )
{
	assert( pprocess );
	assert( pimage );
	assert( pprocess->pbackground );
	assert( pprocess->psegmented );
	assert( pprocess->pROI );
	assert( pimage->width = pprocess->pbackground->width );
	assert( pimage->height = pprocess->pbackground->height );
	assert( pimage->width = pprocess->pROI->width );
	assert( pimage->height = pprocess->pROI->height );

	// clear segmented image
	foreach_pixel( psegmented_pixel, pprocess->psegmented ) *psegmented_pixel = 0;

	// calculate some values
	int bgfactor = pprocess->_int_background_factor * delta_time; // shifted by PRECISION_BITS bits!

	// process pixels
	pixel_t* pimage_pixel = pimage->pixels;
	pixel_t* pbkgnd_pixel = pprocess->pbackground->pixels;
	pixel_t* proi_pixel   = pprocess->pROI->pixels;	
	
	// TODO remove
	//printf("bgfactor=%d, delta time=%d\n", bgfactor, delta_time );
	
	register int x,y; 
	for( y = 0; y < pimage->height; y++ )
	{
		for( x = 0; x < pimage->width; x++ )
		{
			// process:

			// update background
			*pbkgnd_pixel = (uint8_t) ( ( *pbkgnd_pixel * ( (1 << PRECISION_BITS) - bgfactor )
				+ *pimage_pixel * bgfactor ) >> PRECISION_BITS );
			
			// do nothing if out of region of interest
			if ( *proi_pixel )
			{
				// check if pixel's diff from background is above treshold
				if ( abs( *pimage_pixel - *pbkgnd_pixel ) > pprocess->params.foreground_treshold )
				{
					// increment segmented image
					image_pixel
						( pprocess->psegmented
						, x >> pprocess->params.segmentation_scale_log
						, y >> pprocess->params.segmentation_scale_log
						) += ( 1 << ( 8 - 2 * pprocess->params.segmentation_scale_log ) );
						// 8 -max bits in pixel minus pixel number (2^(log*2))
				}
			}
			// increment poniters
			++ pimage_pixel;
			++ pbkgnd_pixel;
			++ proi_pixel;
		}
	}
}

// ============================================================
/// Second stage processing:
///	- changes segmented image into groups. Warning - some groupos will have zero-pixels.
///\param pprocess		- process context
///\note	This function is time-critical, but operates on smaller amount of data than phase 1
static void process_phase2( pprocess_t pprocess )
{
	assert( pprocess );
	assert( pprocess->psegmented );
	assert( pprocess->pgroupmap );
	//assert( pprocess->pROI ); TODO remove if ot sed
	
	// groups joints array
	// this array is in fact a triange array (lower-right half is used).
	// Normally it stores 0, and if groups i and j are conencted, it has 1 in [ min(i,j) ][ max(i,j) ]
	// The array is uninitialized, and each row will be initializwd when new group will bedetected.
	int joints[MAX_GROUPS][MAX_GROUPS];

	// clear groups array and map
	pprocess->groups.clear();

	// cache some data
	const int w = pprocess->psegmented->width;
	const int h = pprocess->psegmented->height;
	
	// go and seek!

	// phase 1 - create initial groups map and groups list
	int x, y, i, j; // indexes
	int*		pmap	= pprocess->pgroupmap->pixels;
	pixel_t*	ppixel	= pprocess->psegmented->pixels;
	for( y = 0; y < h; y++ ) {
		for( x=0; x < w; x++ ) {
			
			// ignore if outside roi
			if (  ( ! pprocess->pROI  || image_pixel
						( pprocess->pROI
						, x << pprocess->params.segmentation_scale_log
						, y << pprocess->params.segmentation_scale_log
						) )
				
			// check treshold
					&& ( *ppixel > pprocess->params.segment_treshold )
				)
			{
				
				int groupabove	= -1;	// group index of pixel above
				int groupbefore	= -1;	// group index of pixel at left
				int currentgroup= -1;	// which group we will choose for current pixel
				
				// find group above
				if ( y > 0 ) {
					// first - look at top-right pixel
					if ( x < w-1 ){
						groupabove = *(pmap-w+1);
					}
					// second - look at pixel at top
					if ( groupabove < 0 ) {
						groupabove = *(pmap-w);
					}
					// lastly - look at pixel at top-left
					if ( groupabove < 0 && x > 0 ) {
						groupabove = *(pmap-w-1);
					}
				}
				// find group at left
				if ( x > 0 ) {
					groupbefore = *(pmap-1);
				}
	
				// if group above exists, take it
				if ( groupabove >= 0 ) {
					currentgroup = groupabove;
					if ( groupbefore >= 0 && groupbefore != groupabove ){
						// connect groups
						joints[ min( groupbefore, groupabove ) ][ max(groupbefore, groupabove ) ] = 1;
					}
				// if there is a group before, take it
				} else if ( groupbefore >= 0 ) {
					currentgroup = groupbefore;
				}
				// if there is a room for motre groups, create new group
				else if ( pprocess->groups.size() < MAX_GROUPS ) {
					// create new group;
					group_t group;
					init_group( group );
					pprocess->groups.push_back( group );
					currentgroup = pprocess->groups.size() - 1;
					// prepare joints
					for( i = 0; i < pprocess->groups.size(); i++ ) {
						joints[i][pprocess->groups.size()-1] = 0;
					}
					
				}
				// no room for more groups, leave pixel ungrouped :(
				
				// assign group to pixel
				*pmap = currentgroup;

				// add pixel to group
				if ( currentgroup >= 0 ){
					add_pixel_to_group( pprocess->groups[ currentgroup ], x, y, *ppixel );
				}

			} // pixel above treshold
			else {
				*pmap = -1; // ignore
			}

			// increment pointers
			pmap ++;
			ppixel ++;
		}
	}

	// phase 2 - merge groups
	// iterate groups, merge higher-numner groups with lower number groups.
	// iterate backwards - so data is cumulated in lower-number groups
	for( i = pprocess->groups.size() - 1 ; i >= 1;  i-- ) {	// from last to 2nd group
		int ac = -1;										// index of last group we were merged with
		for( j = i - 1; j >= 0; j-- ) {						 // from current higher group (i) to first group
			if ( joints[j][i] ){ // j < i, always
				merge_groups( pprocess->groups[ j ], pprocess->groups[ i ] );
				if ( ac >= 0 ) {
					// make sure that 'j' will be conected with 'ac'
					joints[j][ac] = 1;
				}
				ac = j;
				//printf("frame %d, join %d<-%d\n", pprocess->processed_frames, j, i); // TODO remove debug
			}
		}
	}
}

// ============================================================
/// Initializes group structure.
///\par	pgroup	- reference to group object.
///\todo maybe create public?
// TODO make group's constuctor
static void init_group( group_t& group )
{

	// statistics
	group.mx = 0;
	group.my = 0;

	group.minx = 99999;	// TODO or another reasonable max value here, or image width/height
	group.miny = 99999;
	group.maxx = 0;
	group.maxy = 0;

	// counters
	group.value = 0;

	group.pixels = 0;
	group.xsum = 0;
	group.ysum = 0;

}

// ============================================================
/// Adds counters of higher group to lower, leaving counters in higher at zero
///\par	lower	- reference to group object.
///\par	higher	- reference to group object.
// TODO make group's method
static void merge_groups( group_t& lower, group_t& higher )
{
	// add counters
	lower.pixels += higher.pixels;
	lower.xsum += higher.xsum; 
	lower.ysum += higher.ysum;
	lower.value += higher.value;

	// update max/mins
	lower.maxx = max( lower.maxx, higher.maxx );
	lower.maxy = max( lower.maxy, higher.maxy );
	lower.minx = min( lower.minx, higher.minx );
	lower.miny = min( lower.miny, higher.miny );

	// reset counters
	higher.value = 0;

	higher.pixels = 0;
	higher.xsum = 0;
	higher.ysum = 0;
}

// ============================================================
/// Adds pixel to group - updates max/min values, adds pixel value
///\par	group	- reference to group data.
///\par	x		- pixel coord
///\par y		- pixel coord
///\par value	- pixel value
// TODO make group's meth0d
static void add_pixel_to_group( group_t& group, int x, int y, pixel_t value )
{
	// increment counters
	group.xsum += x * value;
	group.ysum += y * value;
	group.pixels++;
	group.value += value;

	// update boundaries
	group.maxx = max( group.maxx, x );
	group.maxy = max( group.maxy, y );
	group.minx = min( group.minx, x );
	group.miny = min( group.miny, y );
}

// ============================================================
/// Checks if group is interesting - if it is not empty, not too small or to big (accroding to process params)
///\par group		- reference to group data
///\par	pprocess	- pointer to process data. Must be valid
///\return	0 if not interesting, 1 otherwise
static int is_interesting_group( group_t& group, pprocess_t pprocess )
{
	assert( pprocess );

	// cache some data:
	// groups siez in segemted pixels (as in group data)
	const int min_group_size = pprocess->params.min_group_size >> pprocess->params.segmentation_scale_log;
	const int max_group_size = pprocess->params.max_group_size >> pprocess->params.segmentation_scale_log;

	// -. check if group wasn't merged - pixels > 0
	if ( group.pixels == 0 )
		return 0; // go away, you don't exists

	// -. check group min size
	if 	(
			( group.maxx - group.minx ) < min_group_size
			||
			( group.maxy - group.miny ) < min_group_size
		)
		return 0; // go away, you are too small!

	// -. check if group max size
	if 	(
			( group.maxx - group.minx ) > max_group_size
			||
			( group.maxy - group.miny ) > max_group_size
		)
		return 0; // go away, you are too big!


	return 1; // success!
	
}

// ============================================================
/// Copies group data into object point. Uses process settings to determine group scaling factor,
///	and suppied timestamp
///\par	pprocess		- pointer to process data. Must be valid
///\par	group			- reference to source group data.
///\par	ppoint (OUT)	- pointer to target points data. Must be valid
///\par timestamp		- point timestamp
static void group_to_point( pprocess_t pprocess, group_t& group, object_point_t* ppoint, uint64_t timestamp )
{
	assert(pprocess);
	assert( ppoint );
	
	int factor = 1 << pprocess->params.segmentation_scale_log;

	ppoint->x = (int) group.mx * factor;
	ppoint->y = (int) group.my * factor;
	ppoint->timestamp = timestamp;

	// if marker set, get its data
	if ( pprocess->pdistance_markers )
	{
		ppoint->marker = image_pixel( pprocess->pdistance_markers, ppoint->x, ppoint->y );
	}
	else
	{
		ppoint->marker = -1;
	}
	
	// if shutter marker set, read it too
	if ( pprocess->pshutter_markers )
	{
		ppoint->shutter = image_pixel( pprocess->pshutter_markers, ppoint->x, ppoint->y );
	}
	else
	{
		ppoint->shutter = -1;
	}
}

// ============================================================
/// Finds mean time of passing time between points. Points should be on diferent
/// areas on image. The functon find time of passiing the boundary between point 1 and point 2
uint64_t find_time( const object_point_t& point1, const object_point_t& point2, pimage_t p_image )
{
	int area1 = image_pixel( p_image, point1.x, point1.y );
	int area2 = image_pixel( p_image, point2.x, point2.y );
	// test - points should be in differents areas
	if ( area1 == area2 )
	{
		printf("points in same areas!\n");
		return point2.timestamp; // fallback
	}
	
	const int time_tolerance		= 1; // acceptable time precission - [ms]
	const int spatial_tolerance		= 3;	// spatail tolerance  - [pixels]
	
	// seek!
	double x1 = point1.x;
	double x2 = point2.x;
	double y1 = point1.y;
	double y2 = point2.y;
	uint64_t time1 = point1.timestamp;
	uint64_t time2 = point2.timestamp;
	double mx, my;
	uint64_t mtime = point2.timestamp; // resu;lt
	while( true )
	{
		// calculte time and spatial difference, break if tolerance reached
		int64_t	time_diff		= time2 - time1;
		double	spatial_diff	= fabs( x2 - x1 ) + fabs( y2 - y1 ); // first module, quick and reliable enough

		// TODO debug, remove
		if ( time_diff < 0 )
		{
			printf("reversed time: %d -> %d \n", (int)time1, (int)time2);
		}
		if ( time_diff < time_tolerance || spatial_diff < spatial_tolerance )
		{
			break;
		}
	
		mtime		= time1 + ( time2 - time1 ) / 2; // causal mean calclation would go out of range
		mx			= ( x1 + x2 ) / 2;
		my			= ( y1 + y2 ) / 2;
		
		// change point1 or point2 to midpoint
		int imx = (int)rint(mx);
		int imy = (int)rint(my);
		if ( image_pixel( p_image, imx, imy ) == area1 )
		{
			x1 = mx;
			y1 = my;
			time1 = mtime;
		}
		else
		{
			x2 = mx;
			y2 = my;
			time2 = mtime;
		}
	}
	
	return mtime;
}

// ============================================================
/// Version of find_time() for 16-bit clocks. Takes care of overload.
uint64_t find_time16( object_point_t& point1, object_point_t& point2, pimage_t p_image )
{
	if ( point2.timestamp < point1.timestamp )
	{
		point2.timestamp += (1<<16); // add carry but on 16th position to (appearently overfulled) timer
	}
	
	return find_time( point1, point2, p_image );
}

// ============================================================
/// Adds group to object
void add_group_to_object( pprocess_t pprocess, object_t* pobject, group_t& group, uint64_t timestamp )
{
	assert( pprocess );
	assert( pobject );
	
	// new point ,from group	
	object_point_t point;
	group_to_point( pprocess, group, &point, timestamp );
	// get last point
	object_point_t& lastPoint = pobject->points.back();
	// apend new point
	pobject->points.push_back( point );
	// note this event
	pobject->lastSeenTime = timestamp;

	// check if marker was passed
	if ( pobject->points.size() > 1 )
	{
		int currentMarker	= point.marker;
		int lastMarker		= lastPoint.marker;
		int currentShutter	= point.shutter;
		int lastShutter		= lastPoint.shutter;

		// cache marker crossing times
		if ( lastMarker == 0 && currentMarker == 1 )
		{
			pobject->marker01Time = find_time16( lastPoint, point, pprocess->pdistance_markers );
			printf("marker 01 passed\n");fflush( stdout ); // TODO remove
		}
		else if ( lastMarker == 1 && currentMarker == 2 )
		{
			pobject->marker12Time = find_time16( lastPoint, point, pprocess->pdistance_markers );
			// try calculate speed
			if ( pobject->marker01Time > 0 )
			{
				pobject->speed = (double)pprocess->reference_distance / (double)( pobject->marker12Time - pobject->marker01Time );
			}
			printf("marker 12 passed, speed calculated: %.2lf (time: %.lf)\n", pobject->speed,
				(double)( pobject->marker12Time - pobject->marker01Time ) );
			fflush( stdout ); // TODO remove
		}
		
		// detect shutter trigger
		if ( lastShutter == 0 && currentShutter == 1 )
		{
			printf("triger marker passed\n");fflush( stdout ); // TODO remove
			pobject->shutterTime = find_time16( lastPoint, point, pprocess->pshutter_markers );
		}
		
	}
	
}

// ============================================================
/// Adds new obejct to process
///\return pointer to added object, or NULL on error
object_t* add_new_object( pprocess_t pprocess )
{
	assert( pprocess );

	object_t object;
	// initialize object
	object.marker01Time	= 0;
	object.marker12Time	= 0;
	object.shutterTime	= 0;
	object.lastSeenTime = 0;
	object.speed			= 0.0;
	
	pprocess->objects.push_back( object );

	return &pprocess->objects.back();
}

// ============================================================
/// Analyzes list of groups in process, and updates list of moving objects accordingly.
///\par	pprocess	- pointer to process data. Must be valid
///\par pimage		- pointer to frame. used to drawe objects on in debug mode. may be NULL
///\par timestamp	- timestamp of currently processed frame
static void process_phase3( pprocess_t pprocess, pimage_t pimage, uint64_t timestamp )
{
	assert( pprocess );

	// for each group
	for( int groupi = 0; groupi < pprocess->groups.size(); groupi++ )
	{
		object_t* closest_object = 0;	// object closest to group
		int closest_distance = -1;	// its distance
		
		// cache some data
		group_t& group = pprocess->groups[ groupi ];

		// check if group applies
		if ( ! is_interesting_group( group, pprocess ) )
			continue;

		// calculate group mean poxition
		group.mx = (double)group.xsum / group.value;
		group.my = (double)group.ysum / group.value;
		
		// debug - draw group
		if ( pprocess->debug_draw && pimage )
		{
			draw_rectangle
				( pimage
				, group.minx << pprocess->params.segmentation_scale_log
				, group.miny << pprocess->params.segmentation_scale_log
				, group.maxx << pprocess->params.segmentation_scale_log
				, group.maxy << pprocess->params.segmentation_scale_log
				);
		}


		
		// find group precedesor
		for( list<object_t>::iterator objecti = pprocess->objects.begin()
				; objecti != pprocess->objects.end(); objecti++ )
		{
			// cache data
			object_t& object = *objecti;

			// is valid?
			if ( object.points.size() > 0 )
			{
				// time difference from group to object
				int delta_time = timestamp - object.points.back().timestamp;
				// spatial distance
				int dx = group.mx - object.points.back().x;
				int dy = group.my - object.points.back().y;
				int distance = abs(dx) + abs(dy);	// 1st module of diff vector

				// is distance within limit?
				if ( pprocess->params.max_group_distance * delta_time < distance * 1000 )
				{
					// is distance smaller than mnimum?
					if ( distance < closest_distance || closest_distance < 0 )
					{
						closest_distance = distance;
						closest_object = &object;
					}
					else
					{
						// TODO debug
						//printf("group rejected, distance: %d\n", distance );
					}
				}
			}
		}

		// add group to closest_object, if exists
		if ( closest_object )
		{
			// if the object was already updated in this frame
			if ( closest_object->points.back().timestamp == timestamp )
			{
				// TODO clone (fork) object here
			}
			// update object, if there is a room for more points, and non static
			else if ( closest_distance > 0  )
			{
				add_group_to_object( pprocess, closest_object, group, timestamp );
			}
		}
		// create new object, if there is a room
		else if ( pprocess->objects.size() < MAX_OBJECTS )
		{
			object_t* pobject	= add_new_object( pprocess );
			if ( pobject )
			{
				add_group_to_object( pprocess, pobject, group, timestamp );
			}
		}
		
	}
	
	// remove outdated object
	
	for( list<object_t>::iterator objecti = pprocess->objects.begin()
			; objecti != pprocess->objects.end(); /* no increment*/ )
	{
		// is outdates?
		if ( timestamp - objecti->lastSeenTime  > pprocess->params.object_timeout )
		{
			// remove object
			objecti = pprocess->objects.erase( objecti );
			//printf("removing timouted object\n"); // TODO remove debug
		}
		else
		{
			// inclrement counter otherwise
			objecti ++;
		}
	}
}

// eof

